#include <sstream>

#include "xpath_static.h"
#include "tinyxml.h"
#include "student.h"
#include "lib.h"

#include "logger.h"
#include "database.h"
#include "lib.h"
#include "exception_xml.hpp"

DataBase::DataBase( const std::string& sFilePath ) throw( utils::Exception )
:
	m_sFilePath( sFilePath )
{
	pthread_mutex_init( &mxDatabase, NULL );
	Reload();
}

DataBase::~DataBase()
{
	Clear();
}

void DataBase::Clear()
{
	for( StudentMap::iterator it = m_mapStudents.begin(); it != m_mapStudents.end(); ++it )
	{
		delete it->second;
	}
	m_mapStudents.clear();
}

std::string DataBase::GetFilePath()
{
	return m_sFilePath;
}

Student* DataBase::Search( int nFN ) throw( utils::Exception )
{
	StudentMap::iterator it = m_mapStudents.find( nFN );
	if( it == m_mapStudents.end() )
	{
		return NULL;
	}

	return it->second;
}

Student* DataBase::Search( std::string sFN ) throw( utils::Exception )
{
	int nFN = 0;
	nFN = utils::StringToNum( sFN );

	return Search( nFN );
}

void DataBase::Reload() throw( utils::Exception )
{
	pthread_mutex_lock( &mxDatabase );

	Clear();

	TiXmlDocument xmlDoc;
	xmlDoc.LoadFile( m_sFilePath.c_str() );
	if( xmlDoc.Error() )
    {
        DBG << "Error loading XML file '" << m_sFilePath << "' at [ "
            << xmlDoc.ErrorRow() << ", "
            << xmlDoc.ErrorCol() << " ]: "
            << xmlDoc.ErrorDesc() << std::endl;

		throw utils::ExceptionXml( "Wrong Database Config XML" );
    }

    TiXmlElement* pRootElement = xmlDoc.RootElement();
    if( NULL == pRootElement )
    {
    	throw utils::ExceptionXml( "Cannot get Database Config XML root element" );
    }

    for( TiXmlElement* pStudentElement = pRootElement->FirstChildElement( "student" );
		 NULL != pStudentElement;
		 pStudentElement = pStudentElement->NextSiblingElement( "student" ) )
	{
		Student* pStudent = new Student( pStudentElement );
		DBG << "Student created successfully: " << pStudent->GetName() << std::endl;
		m_mapStudents.insert( std::make_pair( pStudent->GetFN(), pStudent ) );
	}
	if( m_mapStudents.empty() )
	{
		throw( utils::Exception( "No students in database!" ) );
	}

	pthread_mutex_unlock( &mxDatabase );
}

std::string DataBase::GetAvailableFNsPrintable()
{
	std::stringstream ssFNs;
	for( StudentMap::const_iterator cit = m_mapStudents.begin();
		 cit != m_mapStudents.end();
		 ++cit )
	{
		ssFNs << cit->first << " ";
	}

	return ssFNs.str();
}

